import type { HttpContext } from '@adonisjs/core/http'

import type { WorkSheetOptions } from 'node-xlsx'
import xlsx from 'node-xlsx'

export interface CellAddress {
  c: number
  r: number
}

export interface Range {
  s: CellAddress
  e: CellAddress
}

export function generateExcelResponse(
  response: HttpContext['response'],
  filename: string,
  data: unknown[][],
  options?: WorkSheetOptions
) {
  const mergeRanges = getMergeRanges(data, '0')

  const buffer = xlsx.build([
    {
      name: '数据',
      data,
      options: {
        '!merges': mergeRanges,
        ...options,
      },
    },
  ])

  response.header(
    'Content-Type',
    'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
  )
  response.header(
    'Content-Disposition',
    `attachment; filename=${encodeURIComponent(filename)}.xlsx`
  )
  response.send(buffer)
}

function getMergeRanges(data: any[], keys: string | string[]) {
  const ranges: Range[] = []
  const rangeMap: Map<string, Range> = new Map()

  const keyArr = typeof keys === 'string' ? [keys] : keys

  for (let idx = 0; idx < data.length; idx++) {
    const row = data[idx]
    for (const key of keyArr) {
      let range = rangeMap.get(key)
      if (row[key] === data[idx + 1]?.[key]) {
        if (!range) {
          rangeMap.set(key, {
            s: { c: 0, r: idx },
            e: { c: 0, r: idx + 1 },
          })

          range = rangeMap.get(key)
        } else {
          range.e.r = idx
        }
        continue
      }
      if (range && range.s.r !== range.e.r) {
        ranges.push(range)
        rangeMap.delete(key)
      }
    }
  }

  return ranges
}
